using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Pavilion.Control
{
    public class EditItem : Control
    {
        private Label label;
        private Panel panel;
        private PropertyDescriptor propertyDescriptor;
        private List<DropDownItem> propertyDropDownList;
        private object item;
        private MessageBox messageBox;
        private EditDisplay editDisplay;

        public EditItem(Rectangle bounds, EditDisplay editDisplay) : base()
        {
            this.editDisplay = editDisplay;
            AreaBounds = bounds;
            panel= new Panel(new Rectangle(10, bounds.Height, bounds.Width - 10, 0));
            messageBox = new MessageBox();

            label = new Label("", new Rectangle(0, 0, AreaBounds.Width / 3, AreaBounds.Height), Color.White);
            label.TextAllign = Allign.Left;
            label.TextColor = Color.Black;
            label.TextSize = 0.3f;

            this._Collection.Add(label);
            this._Collection.Add(panel);
        }

        /// <summary>
        /// Sets the property descriptor that is to be displayed.
        /// </summary>
        /// <param name="propertyDescriptor">The property to display.</param>
        /// <param name="item">The associated item.</param>
        public void SetPropertyDescriptor(PropertyDescriptor propertyDescriptor, object item)
        {
            this.propertyDescriptor = propertyDescriptor;
            this.item = item;

            label.Text = propertyDescriptor.DisplayName;
            TextBox textBox = new TextBox(new Rectangle(label.AreaBounds.Width, 0, AreaBounds.Width - label.AreaBounds.Width, AreaBounds.Height));
            textBox.Text = propertyDescriptor.GetValue(item).ToString();
            textBox.TextChanged += new Action<string>(EditItem_TextChanged);

            if (this._Collection.Count > 2)
                this._Collection.RemoveAt(2);

            this._Collection.Add(textBox);
        }

        /// <summary>
        /// Sets the property descriptor that is to be displayed.
        /// </summary>
        /// <param name="propertyDescriptor">The property to display.</param>
        /// <param name="item">The associated item.</param>
        /// <param name="propertyDropDownList">The list of items that can be selected from.</param>
        public void SetPropertyDescriptor(PropertyDescriptor propertyDescriptor, object item, List<DropDownItem> propertyDropDownList)
        {
            this.propertyDescriptor = propertyDescriptor;
            this.item = item;
            this.propertyDropDownList = propertyDropDownList;

            label.Text = propertyDescriptor.DisplayName;
            DropDownList dropDownList = new DropDownList(new Rectangle(label.AreaBounds.Width, 0, AreaBounds.Width - label.AreaBounds.Width, AreaBounds.Height), propertyDropDownList.ToArray());
            object selectedObject = propertyDescriptor.GetValue(item);
            for (int i = 0; i < dropDownList.Count; i++)
            {
                if (selectedObject == null)
                    break;

                if (selectedObject.ToString() == dropDownList[i].AssociatedObject.ToString())
                {
                    dropDownList[i].AssociatedObject = selectedObject;
                    LoadObject(dropDownList[i].AssociatedObject);
                    dropDownList.SelectedItem = dropDownList[i];
                    break;
                }
            }

            dropDownList.ItemSelected += new Action<DropDownItem>(EditItem_ItemSelected);

            if (this._Collection.Count > 2)
                this._Collection.RemoveAt(2);

            this._Collection.Add(dropDownList);
        }

        private void LoadObject(object item)
        {
            panel.Collection.Clear();
            panel.AreaBounds = new Rectangle(panel.AreaBounds.X, panel.AreaBounds.Y, panel.AreaBounds.Width, 0);
            this.AreaBounds = new Rectangle(AreaBounds.X, AreaBounds.Y, AreaBounds.Width, panel.AreaBounds.Height + 20);
            AddObject(item);
        }

        private void AddObject(object item)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(item);

            for (int i = 0; i < properties.Count; i++)
            {
                if (properties[i].Category == "Data")
                    CreateItem(properties, properties[i], item);
                else if (properties[i].Category == "Chain")
                    AddObject(properties[i].GetValue(item));
            }
        }

        private void CreateItem(PropertyDescriptorCollection properties, PropertyDescriptor property, object item)
        {
            int height = panel.AreaBounds.Height;

            EditItem editItem = new EditItem(new Rectangle(0, height, panel.AreaBounds.Width, 20), editDisplay);
            editItem.Resize += new EventHandler(editItem_Resize);

            if (property.Description != "")
                editItem.SetPropertyDescriptor(property, item, (List<DropDownItem>)properties.Find(property.Description, false).GetValue(item));
            else
                editItem.SetPropertyDescriptor(property, item);

            height += editItem.AreaBounds.Height;

            panel.Collection.Add(editItem);

            panel.AreaBounds = new Rectangle(panel.AreaBounds.X, panel.AreaBounds.Y, panel.AreaBounds.Width, height);
            this.AreaBounds = new Rectangle(AreaBounds.X, AreaBounds.Y, AreaBounds.Width, panel.AreaBounds.Height + 20);
        }

        /// <summary>
        /// Gets the object item of item display.
        /// </summary>
        public object Item
        {
            get { return item; }
        }

        private void editItem_Resize(object sender, EventArgs e)
        {
            int height = 0;
            for (int i = 0; i < panel.Collection.Count; i++)
            {
                panel.Collection[i].AreaBounds = new Rectangle(panel.Collection[i].AreaBounds.X, height, panel.Collection[i].AreaBounds.Width, panel.Collection[i].AreaBounds.Height);
                height += panel.Collection[i].AreaBounds.Height;
            }

            panel.AreaBounds = new Rectangle(panel.AreaBounds.X, panel.AreaBounds.Y, panel.AreaBounds.Width, height);
            this.AreaBounds = new Rectangle(AreaBounds.X, AreaBounds.Y, AreaBounds.Width, panel.AreaBounds.Height + 20);
        }

        private void EditItem_TextChanged(string target)
        {
            try
            {
                if (propertyDescriptor.PropertyType == typeof(Single))
                    propertyDescriptor.SetValue(item, Single.Parse(target));
                else if (propertyDescriptor.PropertyType == typeof(Int32))
                    propertyDescriptor.SetValue(item, Int32.Parse(target));
                else
                    propertyDescriptor.SetValue(item, target);
            }
            catch (Exception e)
            {
                messageBox.ShowMessage(e.Message);
            }
        }

        private void EditItem_ItemSelected(DropDownItem dropDownItem)
        {
            propertyDescriptor.SetValue(item, dropDownItem.AssociatedObject);
            editDisplay.Refresh();
        }
    }
}
